/*
 * <h3>Title:wheel-spring-boot-web-starter系统</h3>
 * <p>Copyright (c) 2019, wnfbx@163.com. All rights reserved.</p>
 * @author wnfbx@163.com
 */
package com.wheel.autoconfigure.web.mvc.rest;

import com.wheel.core.utils.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.*;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketAddress;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.List;

/**
 * <dt>Description:RestTemplateAutoConfiguration</dt>
 * <dd>远程访问自动配置</dd>
 *
 * @author wnfbx@163.com
 * @version 1.0 <i>2019年6月6日 下午2:57:54</i>
 * @since jdk1.7+
 */
@ConditionalOnClass(RestTemplate.class)
@EnableConfigurationProperties(RestTemplateProperties.class)
@ConditionalOnProperty(name = "w.spring.rest-template.enable")
public class RestTemplateAutoConfiguration {

    private static final Logger log = LoggerFactory.getLogger(RestTemplateAutoConfiguration.class);

    /**
     * <dt>Description:</dt>
     * <dd>注册 RestTemplate</dd>
     * <dd>author wnfbx@163.com</dd>
     * <dd>version 1.0 <i>2019年6月6日 下午2:57:25</i></dd>
     *
     * @param restTemplateProperties 系统配置参数
     * @return {@link BaseRestTemplate}
     */
    @Bean
    @ConditionalOnMissingBean
    public BaseRestTemplate restTemplate(RestTemplateProperties restTemplateProperties) {
        Log.registered(log, BaseRestTemplate.class.getName());
        RestTemplate build = new RestTemplate();

        SimpleClientHttpRequestFactory requestFactory;
        if (!restTemplateProperties.isEnableSslCheck()) {
            requestFactory = getUnsafeClientHttpRequestFactory();
        } else {
            requestFactory = new SimpleClientHttpRequestFactory();
        }
        build.setRequestFactory(requestFactory);

        requestFactory.setReadTimeout(restTemplateProperties.getReadTimeout());
        requestFactory.setConnectTimeout(restTemplateProperties.getConnectionTimeout());

        if (StringUtils.hasText(restTemplateProperties.getProxyHost())) {
            SocketAddress address = new InetSocketAddress(restTemplateProperties.getProxyHost(), restTemplateProperties.getProxyPort());
            requestFactory.setProxy(new Proxy(restTemplateProperties.getProxyType(), address));
        }

        List<HttpMessageConverter<?>> list = build.getMessageConverters();
        for (HttpMessageConverter<?> httpMessageConverter : list) {
            if(httpMessageConverter instanceof StringHttpMessageConverter) {
                ((StringHttpMessageConverter) httpMessageConverter).setDefaultCharset(Charset.forName(restTemplateProperties.getCharset()));
                break;
            }
        }
        return new BaseRestTemplate(build);
    }


    public static SimpleClientHttpRequestFactory getUnsafeClientHttpRequestFactory() {
        TrustManager[] trustManagers = new TrustManager[]{new X509TrustManager() {

            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }

            public void checkClientTrusted(X509Certificate[] chain, String authType) {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) {
            }
        }};
        final SSLContext sslContext;
//            sslContext = SSLContext.getInstance("TLS");
        // Install the all-trusting trust manager
        try {
            sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustManagers, new java.security.SecureRandom());
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        return new SimpleClientHttpRequestFactory() {
            @Override
            protected void prepareConnection(HttpURLConnection connection,
                                             @NotNull String httpMethod) throws IOException {
                super.prepareConnection(connection, httpMethod);
                if (connection instanceof HttpsURLConnection) {

                    ((HttpsURLConnection) connection).setSSLSocketFactory(sslContext.getSocketFactory());

                    // Create all-trusting host name verifier
                    HostnameVerifier allHostsValid = (hostname, session) -> true;
                    // Install the all-trusting host verifier
                    ((HttpsURLConnection) connection).setHostnameVerifier(allHostsValid);
                }
            }
        };
    }

}